package heap;

import java.io.IOException;
import java.util.LinkedList;

import diskmgr.Page;

import bufmgr.BufMgrException;
import bufmgr.BufferPoolExceededException;
import bufmgr.HashEntryNotFoundException;
import bufmgr.HashOperationException;
import bufmgr.InvalidFrameNumberException;
import bufmgr.PageNotReadException;
import bufmgr.PagePinnedException;
import bufmgr.PageUnpinnedException;
import bufmgr.ReplacerException;

import global.GlobalConst;
import global.PageId;
import global.RID;
import global.SystemDefs;

public class Scan extends Object implements GlobalConst {
	private Heapfile myFile;
	private HFPage pages;
	private LinkedList<PageId> freePages;
	private LinkedList<PageId> fullPages;
	private RID _currRID = null;
	
	public Scan(Heapfile hf) {

		freePages = (LinkedList<PageId>) hf.getFreePages().clone();
		fullPages = (LinkedList<PageId>) hf.getFullPages().clone();
		pages=hf.getPages();
		try {
		//	System.out.println(hf.getPages().firstRecord().pageNo);
			PageId pi = fullPages.removeLast();
			
			SystemDefs.JavabaseBM.pinPage(pi, hf.getPages(), false);
			pages.setCurPage(pi);
			//fullPages.addFirst(pi);
			myFile = hf;

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ReplacerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (HashOperationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (PageUnpinnedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidFrameNumberException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (PageNotReadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BufferPoolExceededException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (PagePinnedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BufMgrException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
private boolean searchForPage(){
	Tuple t = new Tuple();
	if(_currRID == null){
		
		try {
			_currRID = pages.firstRecord();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}else{
		try {
			PageId curr =_currRID.pageNo;
			_currRID = pages.nextRecord(_currRID);
			
			if(_currRID==null){
				try {
					SystemDefs.JavabaseBM.unpinPage(curr, true);
				} catch (ReplacerException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				} catch (PageUnpinnedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				} catch (HashEntryNotFoundException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				} catch (InvalidFrameNumberException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				if(!fullPages.isEmpty()){
					PageId pid = fullPages.removeLast();
					try {
						SystemDefs.JavabaseBM.pinPage(pid, pages, false);
					} catch (ReplacerException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (HashOperationException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (PageUnpinnedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (InvalidFrameNumberException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (PageNotReadException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (BufferPoolExceededException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (PagePinnedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (BufMgrException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					pages.setCurPage(pid);
					
					_currRID=pages.firstRecord();
				}else if(!freePages.isEmpty()){
					PageId pid = freePages.removeLast();
					try {
						SystemDefs.JavabaseBM.pinPage(pid, pages, false);
					} catch (ReplacerException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (HashOperationException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (PageUnpinnedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (InvalidFrameNumberException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (PageNotReadException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (BufferPoolExceededException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (PagePinnedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (BufMgrException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					pages.setCurPage(pid);
					_currRID=pages.firstRecord();
				}else{
					return false;
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	return true;
}
	public Tuple getNext(RID rid) throws InvalidTupleSizeException {
		if(rid == null){
			throw new InvalidTupleSizeException(null, "Invalid tuple.");
		}
		Tuple nextTuple = null;
//		if(_currRID == null){
//			
//			try {
//				_currRID = pages.firstRecord();
//			} catch (IOException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//		}else{
//			try {
//				PageId curr =_currRID.pageNo;
//				_currRID = pages.nextRecord(_currRID);
//				
//				if(_currRID==null){
//					try {
//						SystemDefs.JavabaseBM.unpinPage(curr, true);
//					} catch (ReplacerException e1) {
//						// TODO Auto-generated catch block
//						e1.printStackTrace();
//					} catch (PageUnpinnedException e1) {
//						// TODO Auto-generated catch block
//						e1.printStackTrace();
//					} catch (HashEntryNotFoundException e1) {
//						// TODO Auto-generated catch block
//						e1.printStackTrace();
//					} catch (InvalidFrameNumberException e1) {
//						// TODO Auto-generated catch block
//						e1.printStackTrace();
//					}
//					if(!fullPages.isEmpty()){
//						PageId pid = fullPages.removeLast();
//						try {
//							SystemDefs.JavabaseBM.pinPage(pid, pages, false);
//						} catch (ReplacerException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (HashOperationException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (PageUnpinnedException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (InvalidFrameNumberException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (PageNotReadException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (BufferPoolExceededException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (PagePinnedException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (BufMgrException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						}
//						pages.setCurPage(pid);
//						
//						_currRID=pages.firstRecord();
//					}else if(!freePages.isEmpty()){
//						PageId pid = freePages.removeLast();
//						try {
//							SystemDefs.JavabaseBM.pinPage(pid, pages, false);
//						} catch (ReplacerException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (HashOperationException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (PageUnpinnedException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (InvalidFrameNumberException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (PageNotReadException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (BufferPoolExceededException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (PagePinnedException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						} catch (BufMgrException e) {
//							// TODO Auto-generated catch block
//							e.printStackTrace();
//						}
//						pages.setCurPage(pid);
//						_currRID=pages.firstRecord();
//					}else{
//						return null;
//					}
//				}
//			} catch (IOException e) {
//				// TODO Auto-generated catch block
//				e.printStackTrace();
//			}
//		}
		if(
		!searchForPage()){
			return null;
		}
		try{
			nextTuple = pages.getRecord(_currRID);
			rid.pageNo = new PageId(_currRID.pageNo.pid);
			rid.slotNo = _currRID.slotNo;			
		}catch(Exception exception){
			throw new InvalidTupleSizeException(exception, "Unable to get record.");
		}
		return nextTuple;

		
//		PageId pid = rid.pageNo;
//		try {
//			HFPage hfpage = myFile.getPages();
//			
//			hfpage.setCurPage(pid);
////			Page apage = new Page();
////			hfpage.openHFpage(apage);
//			RID newRid = hfpage.nextRecord(rid);
//			if (newRid == null) {
//				//
//				PageId pageid =null;
//				if(!fullPages.isEmpty()){
//					//get first full page
//			     pageid = fullPages.removeFirst();
//				}else if(!freePages.isEmpty()){
//					 pageid = freePages.pop();
//				}else{
//					//no more pages
//					return null;
//				}
//				myFile.getPages().setCurPage(pageid);
//				newRid = myFile.getPages().firstRecord();
//				rid.pageNo=newRid.pageNo;
//				rid.slotNo=newRid.slotNo;
////				Tuple tup = myFile.getRecord(rid);
////				return tup;
//			}
//			rid.pageNo.pid=newRid.pageNo.pid;
//			rid.slotNo=newRid.slotNo;
//	
//			Tuple t = myFile.getRecord(rid);
//
//			return t;
//		} catch (IOException e) {
//
//			// e.printStackTrace();
//			return null;
//		}

		// return null;
	}

	public boolean position(RID rid) throws InvalidTupleSizeException, IOException {
		if(rid == null || (rid.pageNo.pid < 0) || (rid.slotNo < 0)){
			throw new InvalidTupleSizeException(null, "Invalid tuple.");
		}
		_currRID=rid;
		
		PageId pid = _currRID.pageNo;
//		HFPage hfpage = pages;
		pages.setCurPage(pid);
		_currRID=pages.nextRecord(_currRID);
		if(!searchForPage()){
			return false;
		}else{
			
			return true;
		}
//		try {
//			hfpage.setCurPage(pid);
//			return true;
//		} catch (IOException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		return false;
	}

	public void closescan() {
		PageId pi;
		try {
			//pi = _currRID.pageNo;
			
			SystemDefs.JavabaseBM.unpinPage(pages.curPage, false);
		} catch (ReplacerException e) {
			// TODO Auto-generated catch block
//			e.printStackTrace();
		} catch (PageUnpinnedException e) {
			// TODO Auto-generated catch block
//			e.printStackTrace();
		} catch (HashEntryNotFoundException e) {
			// TODO Auto-generated catch block
//			e.printStackTrace();
		} catch (InvalidFrameNumberException e) {
			// TODO Auto-generated catch block
//			e.printStackTrace();
		}

	}

}
